package com.gitee.wsl.ext.base

import com.gitee.wsl.base.Objects
import kotlin.reflect.KClass

val Objects.Compare
    get() = com.gitee.wsl.ext.base.Compare

fun <T> Comparator<T>.test(a:T,b:T) = compare(a,b) > 0

object Compare{

    fun <V : Any> get(cla: KClass<V>):Comparable<V>? = when(cla){
        Int -> INT
        Short -> SHORT
        else -> null
    } as Comparable<V>?


    /**
     * compare two object
     *
     * **About result**
     *  * if v1 > v2, return 1
     *  * if v1 = v2, return 0
     *  * if v1 < v2, return -1
     *
     *
     * **About rule**
     *  * if v1 is null, v2 is null, then return 0
     *  * if v1 is null, v2 is not null, then return -1
     *  * if v1 is not null, v2 is null, then return 1
     *  * return v1.[Comparable.compareTo]
     *
     *
     * @param v1
     * @param v2
     * @return
     */
    fun <V: Comparable<V>> compare(v1: V?, v2: V?): Int = compareValues(v1,v2) /*{
        return if (v1 == null)
            (v2 == null).ifValue(0,1)
        else
            (v2 == null).ifValue(1,v1.compareTo(v2!!))

    }*/

    fun <V> equals(a: V?, b: V?): Boolean = (a == null && b == null) || a == b

    fun <V:Any> compare(v1: V?, v2: V?,compareCall:(v1:V,v2:V)->Int): Int {
        return if (v1 == null)
            (v2 == null).ifValue(0,-1)
        else
            (v2 == null).ifValue(1,compareCall(v1, v2!!))
    }

    fun<T> NONE() = Comparator<T> { _, _ -> 0 }

    val INT = Comparator<Int> { a, b -> a.compareTo(b) }

    val LONG = Comparator<Long> { a, b -> a.compareTo(b) }

    val FLOAT = Comparator<Float> { a, b -> a.compareTo(b) }

    val DOUBLE = Comparator<Double> { a, b -> a.compareTo(b) }

    val CHAR = Comparator<Char> { a, b -> a.compareTo(b) }

    val UINT = Comparator<UInt> { a, b -> a.compareTo(b) }

    val ULONG = Comparator<ULong> { a, b -> a.compareTo(b) }

    val SHORT = Comparator<Short> { a, b -> a.compareTo(b) }

    val BYTE = Comparator<Byte> { a, b -> a.compareTo(b) }

}

fun <T : Comparable<T>> Compare.comparator(): Comparator<T> = Comparator { a, b -> a.compareTo(b) }

inline fun <V> V.gt(other:V,compareCall:(v1:V, v2:V)->Boolean):Int{
    return compareCall(this,other).ifValue(1,-1)
}

inline fun <V> V.lt(other:V,compareCall:(v1:V, v2:V)->Boolean):Int{
    return compareCall(this,other).ifValue(-1,1)
}

inline fun <V> Pair<V,V>.gt(compareCall:(v1:V, v2:V)->Boolean):Int{
    return first.gt(second,compareCall)
}

fun <V> V?.compare(other:V?, compareCall:(v1:V, v2:V)->Int): Int {
    return Compare.compare(this,other,compareCall)
}

fun <V: Comparable<V>> V?.compare(other:V?): Int {
    return Compare.compare(this,other)
}

fun <V: Comparable<V>> V.betweenInterval(start:V,end:V):Boolean{
    return this.compare(start) > 0 && this.compare(end) < 0
}

//fun <V> Comparator<V>.then(next:Comparator<V>):Comparator<V> = Comparator{a,b->
//    val ret = compare(a, b)
//    if( ret == 0 ) return@Comparator next.compare(a,b)
//    ret
//}

inline fun <T> Compare.compareBy(crossinline selector: (T) -> Comparable<*>?): Comparator<T> = kotlin.comparisons.compareBy(selector)

fun <T> Compare.compareBy(vararg selectors: (T) -> Comparable<*>?): Comparator<T> =
         kotlin.comparisons.compareBy(*selectors)

fun <T> Compare.compareValuesBy(a: T, b: T, vararg selectors: (T) -> Comparable<*>?): Int = kotlin.comparisons.compareValuesBy(a,b,*selectors)

inline fun <T> Compare.compareValuesBy(a: T, b: T, selector: (T) -> Comparable<*>?): Int = kotlin.comparisons.compareValuesBy(a,b,selector)

inline fun <T, K> Compare.compareValuesBy(a: T, b: T, comparator: Comparator<in K>, selector: (T) -> K): Int =
    kotlin.comparisons.compareValuesBy(a,b, comparator, selector)

inline fun <T> Compare.compareByDescending(crossinline selector: (T) -> Comparable<*>?) =
    kotlin.comparisons.compareByDescending(selector)

inline fun <T, K> Compare.compareByDescending(comparator: Comparator<in K>, crossinline selector: (T) -> K): Comparator<T> =
    kotlin.comparisons.compareByDescending(comparator,selector)

fun <T : Any> Compare.nullsFirst(comparator: Comparator<in T>): Comparator<T?> =
    kotlin.comparisons.nullsFirst(comparator)

fun <T : Comparable<T>> Compare.nullsFirst(): Comparator<T?> =
    kotlin.comparisons.nullsFirst()

fun <T : Any> Compare.nullsLast(comparator: Comparator<in T>): Comparator<T?> =
    kotlin.comparisons.nullsLast(comparator)

fun <T : Comparable<T>> Compare.nullsLast(): Comparator<T?> =
    kotlin.comparisons.nullsLast()

fun <T : Comparable<T>> Compare.naturalOrder(): Comparator<T> =
    kotlin.comparisons.naturalOrder()

fun <T : Comparable<T>> Compare.reverseOrder(): Comparator<T> =
    kotlin.comparisons.reverseOrder()

